﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using Blackworks.Logger;
using Monocle.DataModel;
using Monocle.DataModel.CustomDTO;

namespace Monocle.DataProvider
{
    public partial class SqlClient
    {

        /// <summary>
        /// Gets a tUser by his email
        /// </summary>
        /// <param name="email"></param>
        /// <returns>Password stripped tUser</returns>
        public tUser GetUserByEmail(string email)
        {
            var sw = new System.Diagnostics.Stopwatch();
            sw.Start();
            tUser queryResult = null;
            try
            {
                using (var context = new MonocleEntities(_connectionString))
                {
                    // Disable proxies for serialization purposes
                    context.ContextOptions.ProxyCreationEnabled = false;

                    queryResult = (from b in context.tUsers
                                   where b.Email == email
                                   select b).SingleOrDefault();
                }
            }
            catch (Exception e)
            {
                Log.WriteExceptionLogEntry(String.Format("The webmethod {0} failed with Exception: " + Environment.NewLine + "{1}" + Environment.NewLine + "Stacktrace:" + Environment.NewLine + "{2}" + Environment.NewLine + "InnerException: {3}", MethodBase.GetCurrentMethod().Name, e.Message, e.StackTrace, e.InnerException == null ? String.Empty : e.InnerException.Message), LogEntryPriority.Critical);
                throw e;
            }
            finally
            {
                sw.Stop();
                Log.WritePerformanceLogEntry(String.Format("Web method {0} runtime in milliseconds: {1}", MethodBase.GetCurrentMethod().Name, sw.ElapsedMilliseconds), LogEntryPriority.Low);
            }
            return queryResult;
        }

        /// <summary>
        /// Saves a changed user in the database
        /// </summary>
        /// <param name="user">User to be saved</param>
        /// <returns>Saved and updated user</returns>
        public tUser SaveUser(tUser dto)
        {
            var sw = new System.Diagnostics.Stopwatch();
            sw.Start();

            tUser returnValue = dto;
            if (dto == null)
                throw new ArgumentNullException("dto", "argument is not allowed to be null");

            try
            {
                using (var context = new MonocleEntities(_connectionString))
                {
                    if (dto.Version == null)
                    {
                        context.tUsers.AddObject(dto);
                    }
                    else
                    {
                        context.tUsers.Attach(dto);
                        context.ObjectStateManager.ChangeObjectState(dto, EntityState.Modified);
                    }

                    context.SaveChanges();
                    returnValue = dto;
                }
            }
            catch (Exception e)
            {
                Log.WriteExceptionLogEntry(String.Format("The webmethod {0} failed with Exception: " + Environment.NewLine + "{1}" + Environment.NewLine + "Stacktrace:" + Environment.NewLine + "{2}" + Environment.NewLine + "InnerException: {3}", MethodBase.GetCurrentMethod().Name, e.Message, e.StackTrace, e.InnerException == null ? String.Empty : e.InnerException.Message), LogEntryPriority.Critical);
            }
            finally
            {
                sw.Stop();
                Log.WritePerformanceLogEntry(String.Format("Web method {0} runtime in milliseconds: {1}", MethodBase.GetCurrentMethod().Name, sw.ElapsedMilliseconds), LogEntryPriority.Low);
            }
            return returnValue;
        }


        /// <summary>
        /// Get the role of a given user
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public List<tUserRole> GetUsersRoles(tUser user)
        {
            var sw = new System.Diagnostics.Stopwatch();
            sw.Start();
            var queryResult = new List<tUserRole>();
            try
            {
                using (var context = new MonocleEntities(_connectionString))
                {
                    // Disable proxies for serialization purposes
                    context.ContextOptions.ProxyCreationEnabled = false;

                    var GuidRoles = (from b in context.tUser_UserRole where b.FK_tUser == user.PK_tUser select b).ToList();
                    queryResult.AddRange(GuidRoles.Select(gR => (from r in context.tUserRoles where r.PK_tUserRole == gR.FK_tUserRole select r).FirstOrDefault()));
                }
            }
            catch (Exception e)
            {
                Log.WriteExceptionLogEntry(String.Format("The webmethod {0} failed with Exception: " + Environment.NewLine + "{1}" + Environment.NewLine + "Stacktrace:" + Environment.NewLine + "{2}" + Environment.NewLine + "InnerException: {3}", MethodBase.GetCurrentMethod().Name, e.Message, e.StackTrace, e.InnerException == null ? String.Empty : e.InnerException.Message), LogEntryPriority.Critical);
            }
            finally
            {
                sw.Stop();
                Log.WritePerformanceLogEntry(String.Format("Web method {0} runtime in milliseconds: {1}", MethodBase.GetCurrentMethod().Name, sw.ElapsedMilliseconds), LogEntryPriority.Low);
            }
            return queryResult;
        }

        /// <summary>
        /// Get the role of all userroles
        /// </summary>
        /// <returns></returns>
        public List<tUserRole> GetUserRoles()
        {
            var sw = new System.Diagnostics.Stopwatch();
            sw.Start();
            var queryResult = new List<tUserRole>();
            try
            {
                using (var context = new MonocleEntities(_connectionString))
                {
                    // Disable proxies for serialization purposes
                    context.ContextOptions.ProxyCreationEnabled = false;

                    queryResult = (from r in context.tUserRoles select r).ToList();
                }
            }
            catch (Exception e)
            {
                Log.WriteExceptionLogEntry(String.Format("The webmethod {0} failed with Exception: " + Environment.NewLine + "{1}" + Environment.NewLine + "Stacktrace:" + Environment.NewLine + "{2}" + Environment.NewLine + "InnerException: {3}", MethodBase.GetCurrentMethod().Name, e.Message, e.StackTrace, e.InnerException == null ? String.Empty : e.InnerException.Message), LogEntryPriority.Critical);
            }
            finally
            {
                sw.Stop();
                Log.WritePerformanceLogEntry(String.Format("Web method {0} runtime in milliseconds: {1}", MethodBase.GetCurrentMethod().Name, sw.ElapsedMilliseconds), LogEntryPriority.Low);
            }
            return queryResult;
        }

        /// <summary>
        /// Create a new user in the database with a freshly generated random password
        /// </summary>
        /// <param name="dto">DTO of user to create</param>
        /// <returns>User DTO with plaintext password</returns>
        public tUser CreateUser(tUser dto)
        {
            throw new NotImplementedException();
            //var sw = new System.Diagnostics.Stopwatch();
            //sw.Start();

            //tUser returnValue = dto;
            //if (dto == null)
            //    throw new ArgumentNullException("dto", "argument is not allowed to be null");
            //var password = RandomPassword.Generate(6);
            //try
            //{
            //    using (var context = new mCMSEntities(_connectionString))
            //    {
            //        if (dto.Version == null)
            //        {

            //            dto.Password = Crypto.GenerateSaltedHash(password);
            //            context.tUsers.AddObject(dto);
            //        }

            //        context.SaveChanges();
            //        dto.Password = password;
            //        returnValue = dto;
            //    }
            //}
            //catch (Exception e)
            //{
            //    Log.WriteExceptionLogEntry(String.Format("The webmethod {0} failed with Exception: " + Environment.NewLine + "{1}" + Environment.NewLine + "Stacktrace:" + Environment.NewLine + "{2}" + Environment.NewLine + "InnerException: {3}", MethodBase.GetCurrentMethod().Name, e.Message, e.StackTrace, e.InnerException == null ? String.Empty : e.InnerException.Message), LogEntryPriority.Critical);
            //}
            //finally
            //{
            //    sw.Stop();
            //    Log.WritePerformanceLogEntry(String.Format("Web method {0} runtime in milliseconds: {1}", MethodBase.GetCurrentMethod().Name, sw.ElapsedMilliseconds), LogEntryPriority.Low);
            //}
            //return returnValue;
        }
        /// <summary>
        /// Gets all users
        /// </summary>
        /// <returns></returns>
        public List<tUser> GetUsers()
        {
            var sw = new System.Diagnostics.Stopwatch();
            sw.Start();
            List<tUser> queryResult = null;
            var returnList = new List<tUser>();
            try
            {
                using (var context = new MonocleEntities(_connectionString))
                {
                    // Disable proxies for serialization purposes
                    context.ContextOptions.ProxyCreationEnabled = false;

                    queryResult = (from b in context.tUsers
                                   select b).ToList();
                }
            }
            catch (Exception e)
            {
                Log.WriteExceptionLogEntry(String.Format("The webmethod {0} failed with Exception: " + Environment.NewLine + "{1}" + Environment.NewLine + "Stacktrace:" + Environment.NewLine + "{2}" + Environment.NewLine + "InnerException: {3}", MethodBase.GetCurrentMethod().Name, e.Message, e.StackTrace, e.InnerException == null ? String.Empty : e.InnerException.Message), LogEntryPriority.Critical);
                throw e;
            }
            finally
            {
                sw.Stop();
                Log.WritePerformanceLogEntry(String.Format("Web method {0} runtime in milliseconds: {1}", MethodBase.GetCurrentMethod().Name, sw.ElapsedMilliseconds), LogEntryPriority.Low);
            }
            foreach (var tUser in queryResult)
            {
                returnList.Add(tUser);
            }
            return returnList;
        }

        /// <summary>
        /// Gets a user by ID
        /// </summary>
        /// <param name="id"></param>
        /// <returns> tUser</returns>
        public tUser GetUser(Guid id)
        {
            var sw = new System.Diagnostics.Stopwatch();
            sw.Start();
            tUser queryResult = null;
            try
            {
                using (var context = new MonocleEntities(_connectionString))
                {
                    // Disable proxies for serialization purposes
                    context.ContextOptions.ProxyCreationEnabled = false;

                    queryResult = (from b in context.tUsers
                                   where b.PK_tUser == id
                                   select b).SingleOrDefault();
                }
            }
            catch (Exception e)
            {
                Log.WriteExceptionLogEntry(String.Format("The webmethod {0} failed with Exception: " + Environment.NewLine + "{1}" + Environment.NewLine + "Stacktrace:" + Environment.NewLine + "{2}" + Environment.NewLine + "InnerException: {3}", MethodBase.GetCurrentMethod().Name, e.Message, e.StackTrace, e.InnerException == null ? String.Empty : e.InnerException.Message), LogEntryPriority.Critical);
                throw e;
            }
            finally
            {
                sw.Stop();
                Log.WritePerformanceLogEntry(String.Format("Web method {0} runtime in milliseconds: {1}", MethodBase.GetCurrentMethod().Name, sw.ElapsedMilliseconds), LogEntryPriority.Low);
            }

            if (queryResult == null)
                throw new ArgumentException("No match was found for the supplied id", "id");
            return queryResult;
        }

        /// <summary>
        /// Delete user
        /// </summary>
        /// <param name="dto"></param>
        public void DeleteUser(tUser dto)
        {
            var sw = new System.Diagnostics.Stopwatch();
            sw.Start();

            if (dto == null)
                throw new ArgumentNullException("dto", "argument is not allowed to be null");

            try
            {
                using (var context = new MonocleEntities(_connectionString))
                {
                    var user = (from b in context.tUsers where b.PK_tUser == dto.PK_tUser select b).SingleOrDefault();
                    context.tUsers.Attach(user);
                    context.tUsers.DeleteObject(user);
                    context.SaveChanges();
                }
            }
            catch (Exception e)
            {
                Log.WriteExceptionLogEntry(String.Format("The webmethod {0} failed with Exception: " + Environment.NewLine + "{1}" + Environment.NewLine + "Stacktrace:" + Environment.NewLine + "{2}" + Environment.NewLine + "InnerException: {3}", MethodBase.GetCurrentMethod().Name, e.Message, e.StackTrace, e.InnerException == null ? String.Empty : e.InnerException.Message), LogEntryPriority.Critical);
            }
            finally
            {
                sw.Stop();
                Log.WritePerformanceLogEntry(String.Format("Web method {0} runtime in milliseconds: {1}", MethodBase.GetCurrentMethod().Name, sw.ElapsedMilliseconds), LogEntryPriority.Low);
            }
        }

        /// <summary>
        /// Set (and overwrite) the users current roles
        /// </summary>
        /// <param name="user"></param>
        /// <param name="roles"></param>
        public bool SetUserRoles(tUser user, List<Guid> roles)
        {
            var sw = new System.Diagnostics.Stopwatch();
            sw.Start();

            if (user == null)
                throw new ArgumentNullException("", "argument is not allowed to be null");

            try
            {
                using (var context = new MonocleEntities(_connectionString))
                {
                    var userDTO = (from b in context.tUsers where b.PK_tUser == user.PK_tUser select b).SingleOrDefault();
                    var userJunctions =
                        (from b in context.tUser_UserRole where b.FK_tUser == userDTO.PK_tUser select b).ToList();

                    foreach (var tUserUserRole in userJunctions)
                    {
                        context.tUser_UserRole.Attach(tUserUserRole);
                        context.tUser_UserRole.DeleteObject(tUserUserRole);
                    }

                    if (roles != null)
                    {
                        foreach (var role in roles)
                        {
                            var junction = new tUser_UserRole();
                            junction.FK_tUser = userDTO.PK_tUser;
                            junction.FK_tUserRole = role;
                            junction.PK_tUserUserRole = Guid.NewGuid();
                            context.tUser_UserRole.AddObject(junction);
                        }
                    }

                    context.SaveChanges();
                }
            }
            catch (Exception e)
            {
                Log.WriteExceptionLogEntry(String.Format("The webmethod {0} failed with Exception: " + Environment.NewLine + "{1}" + Environment.NewLine + "Stacktrace:" + Environment.NewLine + "{2}" + Environment.NewLine + "InnerException: {3}", MethodBase.GetCurrentMethod().Name, e.Message, e.StackTrace, e.InnerException == null ? String.Empty : e.InnerException.Message), LogEntryPriority.Critical);
                throw e;
            }
            finally
            {
                sw.Stop();
                Log.WritePerformanceLogEntry(String.Format("Web method {0} runtime in milliseconds: {1}", MethodBase.GetCurrentMethod().Name, sw.ElapsedMilliseconds), LogEntryPriority.Low);
            }
            return true;
        }
    }
}
